import urllib2
import time
import gnosis.xml.objectify

baseurl = 'weewar.com'
protocol = 'http://'
# don't spam the weewar server more than once per second
waitseconds = 1.0
# controls debug output
_botdebug = False
retryseconds = 0.5


class WeewarApiLib(object):
  def __init__(self, username=None, apikey=None):
    self.username = username
    self.password = apikey
    if username:
      self.passman = urllib2.HTTPPasswordMgrWithDefaultRealm()
      # this creates a password manager
      self.passman.add_password("users", baseurl, self.username, self.password)
      # because we have put None at the start it will always
      # use this username/password combination for  urls
      # for which `theurl` is a super-url

      authhandler = urllib2.HTTPBasicAuthHandler(self.passman)

      self.opener = urllib2.build_opener(authhandler)
      self.opener.addheaders = [('Content-Type', 'application/xml'), ('Accept', 'application/xml')]
      urllib2.install_opener(self.opener)
      # authentication is now handled automatically for us
    self.lastTime = 0
  def _fetchApiResponse(self, suburl):
    data = None
    while data is None:
      try:
        data = urllib2.urlopen(protocol + baseurl + suburl)
      except urllib2.URLError, e:
        print "URL ERROR:", e
        print "Retrying in %d seconds..." % (retryseconds)
        time.sleep(retryseconds)
        continue
    text = data.read()
    return gnosis.xml.objectify.XML_Objectify(text).make_instance()
  def getHeadquartersInfo(self):
    return self._fetchApiResponse("/api1/headquarters")
  def getUserInfo(self, username):
    return self._fetchApiResponse("/api1/user/"+str(username))
  def getGameState(self, gameid):
    return self._fetchApiResponse("/api1/gameState.jsp?game="+str(gameid))
  def getGameStatus(self, gameid):
    return self._fetchApiResponse("/api1/game/"+str(gameid))
  def getOpenGameList(self):
    return self._fetchApiResponse("/api1/games/open")
  def getUserList(self):
    return self._fetchApiResponse("/api1/users/all")
  def getMapList(self):
    return self._fetchApiResponse("/api1/maps")
  def getMapLayout(self, mapid):
    return self._fetchApiResponse("/api1/mapLayout.jsp?map="+str(mapid))
  def sendBotCommand(self, xmltext):
    # throttle HTTP requests to be a nice bot
    now = time.time()
    diff = now - self.lastTime
    if diff < waitseconds:
      if _botdebug:
        print "waiting..."
      time.sleep(waitseconds-diff)
    self.lastTime = time.time()
    # put together an XML-based request
    url = protocol + baseurl + "/api1/eliza.jsp"
    data = xmltext
    headers = {'Content-Type':'application/xml', 'Accept':'application/xml'}
    text = None
    while text is None:
      try:
        req = urllib2.Request(url, data, headers)
        response = urllib2.urlopen(req)
        text = response.read()
      except urllib2.URLError, e:
        print "URL ERROR:", e
        print "Retrying in %d seconds..." % (retryseconds)
        time.sleep(retryseconds)
        continue
    if _botdebug:
      print data
    return gnosis.xml.objectify.XML_Objectify(text).make_instance()

def _gameXml(gameid, command):
  return "<weewar game='%s'>%s</weewar>" % (str(gameid), str(command))

class WeewarGameControlApi(object):
  def __init__(self, username, apikey):
    self.username = username
    self.api = WeewarApiLib(username, apikey)
  def acceptInvitation(self, gameid):
    if _botdebug:
      print self.username + " is accepting invitation to game %d." % gameid
    return self.api.sendBotCommand(_gameXml(gameid, "<acceptInvitation/>"))
  def declineInvitation(self, gameid):
    if _botdebug:
      print self.username + " is declining invitation to game %d." % gameid
    return self.api.sendBotCommand(_gameXml(gameid, "<declineInvitation/>"))
  def sendReminder(self, gameid):
    if _botdebug:
      print self.username + " is sending reminder for game %d." %gameid
    return self.api.sendBotCommand(_gameXml(gameid, "<sendReminder/>"))
  def surrender(self, gameid):
    if _botdebug:
      print self.username + " is surrendering in game %d." %gameid
    return self.api.sendBotCommand(_gameXml(gameid, "<surrender/>"))
  def abandon(self, gameid):
    if _botdebug:
      print self.username + " is abandoning game %d." %gameid
      print _gameXml(gameid, "<abandon/>")
    return self.api.sendBotCommand(_gameXml(gameid, "<abandon/>"))
  def removeGame(self, gameid):
    if _botdebug:
      print self.username + " is removing game %d." %gameid
    return self.api.sendBotCommand(_gameXml(gameid, "<removeGame/>"))
  def finishTurn(self, gameid):
    if _botdebug:
      print self.username + " finished a turn in game %d." %gameid
    return self.api.sendBotCommand(_gameXml(gameid, "<finishTurn/>"))
  def buildUnit(self, gameid, x, y, unitname):
    if _botdebug:
      print self.username + " is building a %s on %d,%d in game %d" %(unitname, x, y, gameid)
    buildtext = "<build x='%s' y='%s' type='%s' />" % (str(x), str(y), str(unitname))
    return self.api.sendBotCommand(_gameXml(gameid, buildtext))
  def createUnitCommand(self, gameid, x, y):
    if _botdebug:
      print self.username + " is ordering the unit on %d,%d in game %d" %(x, y, gameid)
    unitcmd = "<unit x='%d' y='%d'>%s</unit>" % (x, y, '%s')
    unittext = _gameXml(gameid, unitcmd)
    return unittext
  def sendUnitCommand(self, unitcmd):
    if _botdebug:
      print "  ...unit is done."
    unittext = unitcmd % ''
    return self.api.sendBotCommand(unittext)
  def repairUnit(self, unitcmd):
    if _botdebug:
      print "  ...unit is repairing."
    unitcmd = unitcmd % "<repair />%s"
    return unitcmd
  def captureUnit(self, unitcmd):
    if _botdebug:
      print "  ...unit is capturing."
    unitcmd = unitcmd % "<capture />%s"
    return unitcmd
  # example return XML: <attack target='[4,5]' damageReceived='2' damageInflicted='4' remainingQuantity='8' />
  def attackUnit(self, unitcmd, targetx, targety):
    if _botdebug:
      print "  ...unit is attacking a unit at %d,%d." % (targetx, targety)
    unitcmd = unitcmd % ("<attack x='%d' y='%d' />%s" % (targetx, targety, '%s'))
    return unitcmd
  def moveUnit(self, unitcmd, targetx, targety):
    if _botdebug:
      print "  ...unit is moving to %d,%d."% (targetx, targety)
    unitcmd = unitcmd % ("<move x='%d' y='%d' />%s" % (targetx, targety, '%s'))
    return unitcmd
  def attackOptions(self, gameid, x, y, unitname, moved=0):
    if _botdebug:
      print self.username + " is checking attack options for %s[%d,%d] on move %d in game %d." % (unitname,x,y,moved,gameid)
    text = '<attackOptions x="%d" y="%d" type="%s" moved="%d" />' % (x,y,unitname,moved)
    return self.api.sendBotCommand(_gameXml(gameid, text))
  def moveOptions(self, gameid, x, y, unitname):
    if _botdebug:
      print self.username + " is checking move options for %s[%d,%d] in game %d." % (unitname,x,y,gameid)
    text = '<movementOptions x="%d" y="%d" type="%s" />' % (x,y,unitname)
    return self.api.sendBotCommand(_gameXml(gameid, text))
